/** Fichier définissant une classe représentant les matrices du groupe @f$SO( 3,
 * R )@f$.
 *
 * Ce fichier contient la définition de la classe MatriceSO3.
 *
 * @file MatriceSO3.hpp
 * @author Johan "Solo" Luisier
 *
 * @date 24 Juin 2011
 */
#include "MatriceSO3.hpp"

#include "Utils/Erreur.hpp"

#include <cmath>
#include <iostream>

using namespace std;

/** Constructeur par défaut.
 *
 * Constructeur permettant de créer la matrice identité.
 */
MatriceSO3::MatriceSO3()
    : MatriceO3()
{}

/** Constructeur standard.
 *
 * Constructeur initialisant les colonnes de la matrices avec les
 * images des trois vecteurs de base, lorsque la matrice est vue comme
 * une rotation.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * vaut +1. Une exception du type Erreur est lancée lorsque l'objet
 * n'est pas valide.
 *
 * @param[in] x image de Ox.
 * @param[in] y image de Oy.
 * @param[in] z image de Oz.
 */
MatriceSO3::MatriceSO3(const Vecteur& x, const Vecteur& y, const Vecteur& z)
    : MatriceO3( x, y, z )
{
    verifie();
}

/** Constructeur de copie, permettant de dupliquer une MatriceSO3.
 *
 * Ici pas besoin de vérifier si la matrice à copier a bien un
 * déterminant égal à + 1 : c'est déjà une MatriceS03.
 *
 * @param[in] mat objet à copier.
 */
MatriceSO3::MatriceSO3(const MatriceSO3& mat)
    : MatriceO3( mat )
{}

/** Constructeur permettant de promouvoir une MatriceO3.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * vaut +1. Une exception du type Erreur est lancée lorsque l'objet
 * n'est pas valide.
 *
 * @param[in] mat objet à promouvoir.
 */
MatriceSO3::MatriceSO3(const MatriceO3& mat)
    : MatriceO3( mat )
{
    verifie();
}

/** Constructeur permettant de promouvoir une MatriceGL3.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * vaut +1. Une exception du type Erreur est lancée lorsque l'objet
 * n'est pas valide.
 *
 * @param[in] mat objet à promouvoir.
 */
MatriceSO3::MatriceSO3(const MatriceGL3& mat)
    : MatriceO3( mat )
{
    verifie();
}

/** Constructeur permettant de promouvoir une Matrice3x3.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * vaut +1. Une exception du type Erreur est lancée lorsque l'objet
 * n'est pas valide.
 *
 * @param[in] mat objet à promouvoir.
 */
MatriceSO3::MatriceSO3(const Matrice3x3& mat)
    : MatriceO3( mat )
{
    verifie();
}

/** Destructeur, virtuel pour assurer une séquence d'appel correcte.
 *
 * Le destructeur n'a rien de spécial à faire.
 */
MatriceSO3::~MatriceSO3()
{}

/** Méthode d'affectation, permettant de copier une instance.
 *
 * Une fois la classe mère initialisée, on vérifie que le déterminant
 * vaut +1. Une exception du type Erreur est lancée lorsque l'objet
 * n'est pas valide.
 *
 * @param[in] mat objet à copier.
 *
 * @return référence sur l'instance courante modifiée.
 */
MatriceSO3& MatriceSO3::operator=(const Matrice3x3& mat)
{
    this -> Matrice3x3::operator=( mat );

    verifie();

    return *this;
}

/** Méthode qui vérifie que la matrice fait bien partie du groupe @f$ SO \left(
 * 3 \right) @f$.
 *
 * Méthode qui vérifie que le déterminant de la matrice est +1. Une
 * exception de type Erreur est lancée dans le cas contraire.
 *
 * @throw Erreur si le déterminant n'est pas égal à 1.
 */
void MatriceSO3::verifie() const
{
    if ( abs( determinant() - 1  ) > 1.e-7 )
    {
        cerr << "Déterminant différent de +1 : " << determinant() << endl;
        throw Erreur( false, 0, "Déterminant différent de +1", "MatriceSO3" );
    }
}
